/*
 * Copyright (C) 2021 XRADIO TECHNOLOGY CO., LTD. All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *    1. Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *    2. Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the
 *       distribution.
 *    3. Neither the name of XRADIO TECHNOLOGY CO., LTD. nor the names of
 *       its contributors may be used to endorse or promote products derived
 *       from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
#include <stdlib.h>
#include <securec.h>
#include "driver/chip/private/hal_os.h"
#include "adc_core.h"
#include "driver/chip/hal_adc.h"
#include "hdf_platform.h"
#include "device_resource_if.h"

// HAL_Semaphore voltage_sem;
// #define ADC_VOL_SEM_INIT() HAL_SemaphoreInitBinary(&voltage_sem)
// #define ADC_VOL_SEM_WAIT() HAL_SemaphoreWait(&voltage_sem, HAL_WAIT_FOREVER)
// #define ADC_VOL_SEM_RELEASE() HAL_SemaphoreRelease(&voltage_sem)
// #define ADC_VOL_SEM_DEINIT() HAL_SemaphoreDeinit(&voltage_sem)

static int32_t AdcHostRead(struct AdcDevice *device, uint32_t channel,
               uint32_t *val)
{
    HAL_Status status = HAL_ERROR;
    if (device == NULL) {
        return HDF_FAILURE;
    }
    status = HAL_ADC_Conv_Polling((ADC_Channel)channel, val, 10000);
    if (status != HAL_OK) {
        printf("HAL_ADC_Conv_Polling return: hal_status = %d\n", status);
        return HDF_ERR_DEVICE_BUSY;
    }
    return HDF_SUCCESS;
}

int32_t AdcHostStart(struct AdcDevice *device)
{
    return HDF_SUCCESS;
}
int32_t AdcHostStop(struct AdcDevice *device)
{
    return HDF_SUCCESS;
}
const struct AdcMethod g_adcHostMethod = {
    .read = AdcHostRead,
    .start = AdcHostStart,
    .stop = AdcHostStop,
};

static int32_t AdcDriverBind(struct HdfDeviceObject *device)
{
    if (device == NULL) {
        printf("%s: adc device object is NULL\r\n", __func__);
        return -1;
    }
    return HDF_SUCCESS;
}

static int32_t AttachAdcDevice(struct AdcDevice *adctrl,
                   struct HdfDeviceObject *device)
{
    ADC_InitParam initParam;

    if (device->property == NULL) {
        HDF_LOGD("%s: adc property is NULL\n", __func__);
        return HDF_FAILURE;
    }

    struct DeviceResourceIface *dri =
        DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE);
    if (dri == NULL || dri->GetUint32 == NULL) {
        HDF_LOGD("DeviceResourceIface is invalid\n");
        return HDF_FAILURE;
    }
    dri->GetUint32(device->property, "work_clk", &initParam.work_clk, 0);
    printf("work_clk = %d\n", initParam.work_clk);
    dri->GetUint32(device->property, "delay", &initParam.delay, 0);
    printf("delay = %d\n", initParam.delay);
    dri->GetUint32(device->property, "suspend_bypass",
               &initParam.suspend_bypass, 0);
    printf("suspend_bypass = %d\n", initParam.suspend_bypass);
    dri->GetUint32(device->property, "vref_mode", &initParam.vref_mode, 0);
    printf("vref_mode = %d\n", initParam.vref_mode);
    dri->GetUint32(device->property, "mode", &initParam.mode, 0);
    printf("mode = %d\n", initParam.mode);
    // ADC_VOL_SEM_INIT();
    return (int32_t)HAL_ADC_Init(&initParam);
}

static int32_t AdcDriverInit(struct HdfDeviceObject *device)
{
    struct AdcDevice *AdcCntrl = NULL;

    if (device == NULL) {
        printf("%s: device is NULL\r\n", __func__);
        return HDF_ERR_INVALID_OBJECT;
    }

    if (AttachAdcDevice(AdcCntrl, device) != HAL_OK) {
        printf("%s: adc init fail!\r\n", __func__);
        return HDF_FAILURE;
    }

    AdcCntrl = malloc(sizeof(struct AdcDevice));
    if (AdcCntrl == NULL) {
        return HDF_ERR_MALLOC_FAIL;
    }
    memset(AdcCntrl, 0, sizeof(struct AdcDevice));

    AdcCntrl->ops = &g_adcHostMethod;
    /* 用于去初始化时释放内存 */
    device->priv = (void *)AdcCntrl;

    int ret = AdcDeviceAdd(AdcCntrl);
    if (ret != HDF_SUCCESS) {
        printf("adcCntlrAdd failed!!ret = %d\n", ret);
        return HDF_FAILURE;
    }
    return ret;
}

static int32_t AdcDriverRelease(struct HdfDeviceObject *device)
{
    if (HAL_ADC_DeInit() != HAL_OK) {
        return HDF_FAILURE;
    }
    // ADC_VOL_SEM_DEINIT();
    free(device->priv);
    return HDF_SUCCESS;
}

/* HdfDriverEntry definitions */
struct HdfDriverEntry g_adcDriverEntry = {
    .moduleVersion = 1,
    .moduleName = "XRADIO_ADC",
    .Bind = AdcDriverBind,
    .Init = AdcDriverInit,
    .Release = AdcDriverRelease,
};

// Initialize HdfDriverEntry
HDF_INIT(g_adcDriverEntry);
